#include "TcpConnection.hpp"
#include <sstream>

namespace wd
{

TcpConnection::TcpConnection(int fd)
: _sock(fd)
, _sockIO(fd)
, _localAddr(getLocalAddress())
, _peerAddr(getPeerAddress())
{

}

TcpConnection::~TcpConnection()
{
    printf("~TcpConnection()\n");
}

string TcpConnection::recieve()
{
    // 在栈上设置的 64KB 空间
    char buff[65536] = {0};
    // 设置第二个参数 ret，是为了防止字符串内容中间有'\0'
    int ret = _sockIO.readline(buff , sizeof(buff));

    return string(buff , ret);
}

void TcpConnection::send(const string & msg)
{
    if(msg.size() > 0)
    {
        _sockIO.sendn(msg.c_str() , msg.length());
    }
}

bool TcpConnection::isClosed() const
{
    char buff[20] = {0};
    return _sockIO.recvPeek(buff , sizeof(buff)) == 0;
}

void TcpConnection::shutdown()
{
    _sock.shutdownWrite();
}

string TcpConnection::toString() const
{
    std::ostringstream oss;
    oss << "TCP " << _localAddr.ip() << ":" << _localAddr.port()
        << " -> " << _peerAddr.ip()  << ":" << _peerAddr.port();

    return oss.str();
}

void TcpConnection::handleNewConnectionCallback()
{
    if(_onConnection)
    {
        // 在成员函数内部获取本对象的智能指针 shared_ptr
        // shared_ptr<TcpConnection> sp(this); // error ,导致智能指针误用
        // this -> shared_ptr
        // 正确方案：TcpConnection 继承自辅助类 std::enable_shared_from_this
        // 继承之后，该类就拥有了一个成员函数 shared_from_this
        _onConnection(shared_from_this());
    }
}

void TcpConnection::handleMessageCallback()
{
    if(_onMessage)
    {
        _onMessage(shared_from_this());
    }
}

void TcpConnection::handleCloseCallback()
{
    if(_onClose)
    {
        _onClose(shared_from_this());
    }
}

InetAddress TcpConnection::getLocalAddress()
{
    struct sockaddr_in addr;
    memset(&addr , 0 , sizeof(addr));
    socklen_t len = sizeof(addr);
    int ret = getsockname(_sock.fd() , (struct sockaddr *)&addr , &len);

    if(ret < 0)
    {
        perror("getsockname");
    }

    return InetAddress(addr);
}

InetAddress TcpConnection::getPeerAddress()
{
    struct sockaddr_in addr;
    memset(&addr , 0 , sizeof(addr));
    socklen_t len = sizeof(addr);
    int ret = getpeername(_sock.fd() , (struct sockaddr *)&addr , &len);

    if(ret < 0)
    {
        perror("getpeername");
    }

    return InetAddress(addr);
}

} // end of namespace wd
